﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Windows;
using DotNetApp.Toolkit.Utilities;
using Microsoft.Phone.Net.NetworkInformation;
using Microsoft.Phone.Scheduler;
using Microsoft.Phone.Shell;
using Newtonsoft.Json;
using WinSource.Client;
using WinSource.Model;

namespace WinSource.Agent
{
    public class ScheduledAgent : ScheduledTaskAgent
    {
        #region Constants

        private const string LastUpdateVerificationPropertyName = "LastUpdateVerification";
        private const string ArticlesFilename = "Articles.txt";

        #endregion

        #region Fields

        private static volatile bool _classInitialized;
        private WinSourceClient _winSourceClient;
        private DateTime _lastCheck;

        #endregion

        #region Constructor

        public ScheduledAgent()
        {
            if (!_classInitialized)
            {
                _classInitialized = true;

                Deployment.Current.Dispatcher.BeginInvoke(delegate { Application.Current.UnhandledException += ScheduledAgent_UnhandledException; });
            }
        }

        #endregion

        #region Event Handlers

        protected override void OnInvoke(ScheduledTask task)
        {
            _lastCheck = (DateTime)GetApplicationSettingValue(LastUpdateVerificationPropertyName, new DateTime(1, 1, 1));

            if (_lastCheck.Year != 1)
            {
                if (IsUpdateRequired())
                {
                    Update();
                }
                else
                {
                    NotifyComplete();
                }
            }
            else
            {
                SaveSettingValueImmediately(LastUpdateVerificationPropertyName, DateTime.Now);
                NotifyComplete();
            }
        }

        private void ScheduledAgent_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                System.Diagnostics.Debugger.Break();
            }
        }

        #endregion

        #region Private Methods

        private bool IsUpdateRequired()
        {
            DateTime now = DateTime.Now;

            return (now - _lastCheck).TotalHours > 3;
        }

        private void Update()
        {
            SaveSettingValueImmediately(LastUpdateVerificationPropertyName, DateTime.Now);

            NetworkInformationUtility.GetNetworkTypeCompleted += GetNetworkTypeCompleted;

            NetworkInformationUtility.GetNetworkTypeAsync(1000);
        }

        private void GetNetworkTypeCompleted(object sender, NetworkTypeEventArgs networkTypeEventArgs)
        {
            if (networkTypeEventArgs.Type == NetworkInterfaceType.Wireless80211 || networkTypeEventArgs.Type == NetworkInterfaceType.Ethernet)
            {
                _winSourceClient = new WinSourceClient();

                _winSourceClient.GetArticles(delegate(GetArticlesRequestArgs getArticlesRequestArgs)
                                                 {
                                                     try
                                                     {
                                                         if (getArticlesRequestArgs.IsSuccess)
                                                         {
                                                             uint newArticlesCount = 0;
                                                             List<Article> savedArticles = LoadArticles();
                                                             Article newArticle = null;

                                                             foreach (Article article in getArticlesRequestArgs.Articles)
                                                             {
                                                                 bool isNew = savedArticles.All(savedArticle => article.Id != savedArticle.Id);

                                                                 if (isNew)
                                                                 {
                                                                     newArticlesCount++;

                                                                     if (newArticle == null)
                                                                     {
                                                                         newArticle = article;
                                                                     }
                                                                 }
                                                             }

                                                             if (newArticlesCount > 0)
                                                             {
                                                                 UpdateNotifications((int)newArticlesCount, newArticle);
                                                             }
                                                         }
                                                         else
                                                         {
                                                             NotifyComplete();
                                                         }
                                                     }
                                                     catch
                                                     {
                                                         NotifyComplete();
                                                     }
                                                 });
            }
            else
            {
                NotifyComplete();
            }
        }

        private void UpdateNotifications(int newArticlesCount, Article newArticle)
        {
            Settings settings = (Settings)GetApplicationSettingValue("Settings", new Settings());
            newArticlesCount = (int)GetApplicationSettingValue("LastNewArticlesCount", 0) + newArticlesCount;

            ShellTile appTile = ShellTile.ActiveTiles.First();

            if (appTile != null)
            {
                appTile.Update(new StandardTileData { Count = newArticlesCount, BackContent = newArticle.Title, BackTitle = "WinSource"});

                SaveSettingValueImmediately("LastNewArticlesCount", newArticlesCount);
            }

            if (settings.IsToastNotificationUsed)
            {
                ShellToast shellToast = new ShellToast { Content = string.Format("{0} new article{1}", newArticlesCount, newArticlesCount > 1 ? "s" : ""), Title = "WinSource" };
                shellToast.Show();
            }
        }

        private static object GetApplicationSettingValue(string propertyName, object defaultValue = null)
        {
            object result = null;

            try
            {
                if (!IsolatedStorageSettings.ApplicationSettings.TryGetValue(propertyName, out result))
                {
                    result = defaultValue;
                }
            }
            catch
            {
            }

            return result;
        }

        public static void SaveSettingValueImmediately(string propertyName, object value)
        {
            try
            {
                IsolatedStorageSettings.ApplicationSettings[propertyName] = value;
                IsolatedStorageSettings.ApplicationSettings.Save();
            }
            catch
            {
            }
        }

        public List<Article> LoadArticles()
        {
            List<Article> articles = new List<Article>();

            try
            {
                using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (isolatedStorageFile.FileExists(ArticlesFilename))
                    {
                        using (IsolatedStorageFileStream stream = isolatedStorageFile.OpenFile(ArticlesFilename, FileMode.Open))
                        {
                            using (TextReader textReader = new StreamReader(stream))
                            {
                                string json = textReader.ReadToEnd();

                                articles = JsonConvert.DeserializeObject<List<Article>>(json);
                            }
                        }
                    }
                }

                if (articles == null)
                {
                    articles = new List<Article>();
                }
            }
            catch
            {
            }

            return articles;
        }

        public void SaveArticles(List<Article> articles)
        {
            try
            {
                using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (IsolatedStorageFileStream stream = isolatedStorageFile.CreateFile(ArticlesFilename))
                    {
                        using (TextWriter textWriter = new StreamWriter(stream))
                        {
                            string jsonArticles = JsonConvert.SerializeObject(articles);

                            textWriter.Write(jsonArticles);
                        }
                    }
                }
            }
            catch
            {
            }
        }

        #endregion
    }
}